package com.kuang.service;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.kuang.pojo.Commodity;
import com.kuang.utils.HtmlParseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @description: 商品相关业务逻辑
 * @author: wuhaohua
 * @date: Created in 2022/4/10 20:33
 * @version: 1.0
 */
@Service
public class CommodityService {

    @Autowired
    private ElasticsearchClient client;

    // ES索引名称
    private static final String ES_INDEX = "jd_goods";

    /**
     * 解析商品信息
     *
     * @param keyword 搜索商品的关键字
     * @return {@link Boolean} 解析成功返回true，失败返回false
     * @throws
     * @author: wuhaohua
     * @date: 2022/4/10
     **/
    public Boolean parseCommodity(String keyword) {
        // 解析数据
        List<Commodity> commodityList = null;
        try {
            commodityList = new HtmlParseUtil().parseJD(keyword);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        if (commodityList == null || commodityList.size() < 1) {
            return false;
        }
        // 把查询出来的数据批量放入ES中
        List<BulkOperation> bulkOperationList = new ArrayList<>();
        for (Commodity commodity : commodityList) {
            bulkOperationList.add(BulkOperation.of(fn -> fn
                            .index(io -> io
                                    .id(commodity.getId())
                                    .document(commodity)
                            )
                    )
            );
        }
        try {
            BulkResponse bulkResponse = client.bulk(builder -> builder
                    .index(ES_INDEX)
                    .operations(bulkOperationList)
            );
            // 如果执行出现错误，则返回失败
            if (bulkResponse.errors()) {
                List<BulkResponseItem> items = bulkResponse.items();
                for (BulkResponseItem item : items) {
                    System.out.println(item.error().reason());
                }
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    /**
     * 从ES中搜索相关的数据
     *
     * @param keyword  搜索关键字
     * @param pageNum  页码
     * @param pageSize 页面大小
     * @return {@link List<Commodity>} 搜索结果
     * @author: wuhaohua
     * @date: 2022/4/10
     **/
    public List<Commodity> searchPage(String keyword, int pageNum, int pageSize) throws IOException {
        if (pageNum < 1) {
            pageNum = 1;
        }

        // 计算分页偏移量的起始值
        int from = (pageNum - 1) * pageSize;

        // 条件搜索
        SearchResponse<Commodity> commoditySearchResponse = client.search(s -> s
                .index(ES_INDEX)
                .from(from)
                .size(pageSize)
                .query(q -> q
                        .match(m -> m
                                .field("title")
                                .query(keyword)
                        )
                ), Commodity.class);
        if (commoditySearchResponse == null || commoditySearchResponse.hits() == null || commoditySearchResponse.hits().hits() == null || commoditySearchResponse.hits().hits().size() < 1) {
            System.out.println("未查询到相关数据");
            return null;
        }
        List<Commodity> result = new ArrayList<>();
        for (Hit<Commodity> hit : commoditySearchResponse.hits().hits()) {
            result.add(hit.source());
        }

        return result;
    }

    /**
     * 高亮搜索
     *
     * @param keyword 搜索的关键字
     * @param pageNum 页码
     * @param pageSize 页面大小
     * @return {@link List< Commodity>} 搜索结果
     * @author: wuhaohua
     * @date: 2022/4/23
     **/
    public List<Commodity> searchHighLightPage(String keyword, int pageNum, int pageSize) throws IOException {
        if (pageNum < 1) {
            pageNum = 1;
        }

        // 计算分页偏移量的起始值
        int from = (pageNum - 1) * pageSize;

        // 条件搜索
        SearchResponse<Commodity> commoditySearchResponse = client.search(s -> s
                .index(ES_INDEX)
                .from(from)
                .size(pageSize)
                .highlight(h -> h
                        .requireFieldMatch(false)       // 只需要第一次匹配的地方高亮
                        .fields("title", fn -> fn   // 设置高亮字段
                                .preTags("<span style='color:red'>")   // 设置高亮标签的前缀
                                .postTags("</span>")                    // 设置高亮标签的后缀
                        )
                )
                .query(q -> q
                        .match(m -> m
                                .field("title")
                                .query(keyword)
                        )
                ), Commodity.class);
        if (commoditySearchResponse == null || commoditySearchResponse.hits() == null || commoditySearchResponse.hits().hits() == null || commoditySearchResponse.hits().hits().size() < 1) {
            System.out.println("未查询到相关数据");
            return null;
        }
        List<Commodity> result = new ArrayList<>();
        for (Hit<Commodity> hit : commoditySearchResponse.hits().hits()) {
            // 搜索出来的结果
            Commodity commodityTemp = hit.source();
            // 解析高亮的字段
            if (hit.highlight() != null && hit.highlight().get("title") != null) {
                // 如果有高亮内容，则替换标题
                List<String> hightLightTitleList = hit.highlight().get("title");
                if (hightLightTitleList.size() > 0) {
                    String newTitle = "";
                    for (String highLightTemp: hightLightTitleList) {
                        newTitle += highLightTemp.trim();
                    }
                    if (!newTitle.trim().equals("")) {
                        commodityTemp.setTitle(newTitle);
                    }
                }
            }
            result.add(commodityTemp);
        }

        return result;
    }
}
